In diesem Kapitel schauen wir uns das Eventhandling in JavaScript an. Die einfachste Art des Eventhandling ist es, eine JavaScript-Funktion über das onclick-Attribut eines HTML-Buttons einzubinden. Weitere mögliche Ereignisse sind beispielsweise onload oder onmouseover. In diesem Code wird bei einem Klick auf den Button die JavaScript-Funktion onclick-handler aufgerufen. Solche Attribute sollten nach heutigem Stand jedoch nicht mehr verwendet werden. Christian Heilmann entwickelte den Begriff Unobtrusive JavaScript, also unaufdringliches oder auch barrierefreies JavaScript. Die Interaktivität soll stattdessen dem Dokument automatisch hinzugefügt werden. Im HTML-Code sollte sich also kein JavaScript in Form von Eventhandler-Attributen befinden, sondern beim Laden des Dokuments sollten die Scripte automatisch starten und die Ereignisüberwachung an den betreffenden Elementen übernehmen. Im Idealfall sollte im head-Element ein script-Element stehen, um eine externe JavaScript-Datei einzubinden, die dann ihrerseits aktiv wird und die Eventhandler an die jeweiligen Elemente anbringt. Dazu können Elemente, denen ein bestimmtes Verhalten hinzugefügt werden soll, mit einer Klasse markiert oder mit einer ID ausgezeichnet werden. Mischen Sie also kein JavaScript mit HTML, sondern hängen Sie Eventhandler dynamisch an HTML-Elemente an. Trennen Sie CSS-Anweisungen von JavaScript-Code. Definieren Sie die Formatierungsregeln in einem zentralen Stylesheet, nicht im JavaScript, und sorgen Sie dafür, dass diese Regeln dynamisch angewendet werden, indem Sie beispielsweise einem Element per JavaScript eine Klasse hinzufügen. Man kann in JavaScript einen Event-Listener mittels "element.addEventListener" hinzufügen. Falls der Event Handler nicht mehr ausgeführt werden soll, muss er mittels "element.removeEventListener" wieder entfernt werden. Auf diese Weise können beliebig viele Handler für ein Event auf einem Element erstellt werden. Es ist auch möglich, ihn direkt im HTML oder durch "element.onEventname" hinzuzufügen. Dabei kann jedoch nur ein Handler benutzt werden. Schauen wir uns einmal einen solchen dynamischen Handler an. Zunächst etwas CSS-Code für ein main-Element: Es gibt einen Innenabstand, eine maximale Breite und eine Hintergrundfarbe. "Outline" bestimmt alle vier Außenlinien eines Elements. Im Unterschied zu border wird die outline nicht als Teil des Box-Modells zur Elementgröße hinzugerechnet, sondern als letzter Schritt draufgemalt, ohne Platz wegzunehmen. Im HTML-Body gibt es keine JavaScript-Anteile mehr. Es gibt eine Überschrift und dieses main-Element. Das main-Element besteht aus einem Absatz, einem Button ohne Funktion sowie einem noch versteckten Absatz mit der ID "message". Der JavaScript-Code fügt die Event-Listener erst dann hinzu, wenn der gesamte DOM-Baum geladen ist. Dies ist nötig, da die HTML-Elemente existieren müssen, auf die der Event-Listener angewendet wird. So kann der Code auch oben im HTML-Head eingebaut werden. In der anonymen Funktion wird dann der Button ermittelt und das Klick-Event gewählt. Es wird angegeben, dass bei einem Klick auf den Button die Funktion "handler-for-button" ausgeführt wird. Diese sucht im DOM-Baum nach dem Button-Klick das main-Element und fügt diesem ein Klick-Handler hinzu. Wenn dann auf das main-Element geklickt wird, wird die Funktion "handler-for-main" ausgeführt. Diese wiederum sucht die ID des versteckten Absatzes und macht diesen sichtbar. Probieren Sie es aus! Das DOMContentLoaded-Event ist besonders nützlich, wenn das JavaScript bereits im head oder an anderer Stelle steht, bevor der Browser das komplette HTML in das DOM eingefügt hat. Scripte laufen dann Gefahr, auf Elemente zuzugreifen, die noch nicht existieren. Mit DOMContentLoaded kann man sicherstellen, dass erst mit der Initialisierungslogik begonnen wird, wenn der Browser den gesamten HTML-Baum geparst hat. Dadurch können unmittelbar nach dem Parsen neue Elemente erzeugt, Event-Listener gebunden oder Klassen hinzugefügt werden, ohne Null-Referenz-Fehler befürchten zu müssen. Außerdem trennt diese zentrale Initialisierung die Struktur des HTML sauber von der Logik des JavaScript. Statt Inline-Skripten bündeln wir die Start-Prozedur in einem Handler, was Wartung und Testbarkeit verbessert. DOMContentLoaded wartet im Unterschied zum load-Event nicht auf externe Ressourcen wie Bilder, Stylesheets oder iFrames, weshalb das JavaScript früher aktiv werden kann. Insgesamt ist das DOMContentLoaded-Event eine elegante und performante Methode, um die Ausführung des Codes genau dann zu starten, wenn die DOM-Struktur vollständig bereitsteht – unabhängig von möglicherweise noch zu ladenden Mediendateien. Ein weiterer wichtiger Punkt ist das einheitliche Cross-Browser-Verhalten: Das DOMContentLoaded-Event ist in allen modernen Browsern standardisiert und zuverlässiger als selbstgestrickte Polling-Mechanismen. Alternativ dazu kann man sein Skript ganz ans Ende des body-Elements verschieben. Dann sind beim Laden alle HTML-Elemente bereits geparst und im DOM verfügbar, sodass man ohne zusätzlichen Event-Listener direkt auf die Elemente zugreifen kann. Wichtig ist, dass ein Script hinter dem schließenden html-Tag technisch ungültig ist und von Browsern allenfalls stillschweigend korrigiert wird, was in XML- oder XHTML-Umgebungen zu Problemen führen kann. Deshalb sollte man den Script-Block immer direkt vor dem Ende des body platzieren, wenn man auf einen DOMContentLoaded-Handler verzichten möchte. Auf der Folie sehen wir das gewohnte Formular-Markup, bei dem ein Button mit "type=submit" automatisch das submit-Event des Formulars auslöst. Sobald der Nutzer auf Abschicken klickt, würde der Browser normalerweise unmittelbar eine Anfrage an den Server senden. Genau an dieser Stelle setzen wir unsere Validierungslogik an: Wir registrieren einen Listener auf das submit-Ereignis und prüfen darin, ob die Eingabe die geforderte Mindestlänge erfüllt. Ist die Eingabe zu kurz, verhindern wir mit "preventDefault" das Absenden und können dem Nutzer eine entsprechende Fehlermeldung anzeigen, ohne die Seite neu zu laden. Durch den Einsatz eines echten Submit-Buttons behalten wir außerdem das native Verhalten und die Möglichkeit eines serverseitigen Fallbacks bei. Auf der nächsten Folie sehen wir die Variante mit einem ganz normalen Button, der von sich aus kein Formular abschickt. Im Formular gibt es wie gewohnt ein Textfeld für den Benutzernamen und eine Stelle für eine Fehlermeldung. Anstelle eines submit-Buttons nutzen wir einen einfachen Button, dem wir per JavaScript einen Klick-Handler zuweisen. Beim Klick prüfen wir, ob der eingegebene Text mindestens sechs Zeichen lang ist. Ist die Eingabe zu kurz, zeigen wir dem Nutzer die Fehlermeldung an und verzichten auf das programmatische Auslösen des Formular-submits. Liegt die Eingabe dagegen im erlaubten Bereich, rufen wir per Skript die Methode auf, die das Formular an die definierte Ziel-URL absendet. So behalten wir die Kontrolle über Validierungs- und Versandprozess komplett in JavaScript, während der Button selbst kein Standard-submit auslöst.